package gui;

/**
 * @author dotekien
 * Date: Apr 2, 2006
 * Time: 1:17:45 PM
 * To change this template use File ||
 */
/* Modify ProgressMonitor.java --
*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SameProgressMonitor {
    /**
     * parentComponent
     */
    Component component;

    /**
     * note
     */
    String note;

    /**
     * message
     */
    Object message;

    /**
     * MILLIS_TO_DECIDE_TO_POPUP
     */
    private static final int MILLIS_TO_DECIDE_TO_POPUP = 500;

    /**
     * millisToPopup
     */
    int millisToPopup = 1000;

    int min, max, progress;

    JProgressBar progressBar;

    JTextArea noteTextArea;
    JScrollPane scrollPane;

    JDialog progressDialog;

    Timer timer;

    boolean canceled;

    /**
     * Creates a new <code>ProgressMonitor</code> instance.  This is used to
     * monitor a task and pops up a dialog if the task is taking a long time to
     * run.
     *
     * @param component The parent component of the progress dialog or
     *                  <code>null</code>.
     * @param message   A constant message object which works in the way it does
     *                  in {@link JOptionPane}.
     * @param note      A string message which can be changed while the operation goes
     *                  on.
     * @param minimum   The minimum value for the operation (start value).
     * @param maximum   The maximum value for the operation (end value).
     */
    public SameProgressMonitor(Component component, Object message,
                               String note, int minimum, int maximum) {

        // Set data.
        this.component = component;
        this.message = message;
        this.note = note;

        min = minimum;
        max = maximum;
    }

    /**
     * <p>Hides the dialog and stops any measurements.</p>
     * <p/>
     * <p>Has no effect when <code>setProgress</code> is not at least
     * called once.</p>
     */
    public void close() {
        if (progressDialog != null) {
            progressDialog.setVisible(false);
        }

        if (timer != null) {
            timer.stop();
            timer = null;
        }
    }

    /**
     * <p>Updates the progress value.</p>
     * <p/>
     * <p>When called for the first time this initializes a timer
     * which decides after <code>MILLIS_TO_DECIDE_TO_POPUP</code> time
     * whether to show a progress dialog or not.</p>
     * <p/>
     * <p>If the progress value equals or exceeds the maximum
     * value the progress dialog is closed automatically.</p>
     *
     * @param progress New progress value.
     */
    public void setProgress(int progress) {
        this.progress = progress;

        // Initializes and starts a timer with a task
        // which measures the duration and displays
        // a progress dialog if neccessary.
        if (timer == null && progressDialog == null) {
            timer = new Timer(25, null);
            timer.addActionListener(new TimerListener());
            timer.start();
        }

        // Cancels timer and hides progress dialog if the
        // maximum value is reached.
        if (progressBar != null && this.progress >= progressBar.getMaximum()) {
            // The reason for using progressBar.getMaximum() instead of max is that
            // we want to prevent that changes to the value have any effect after the
            // progress dialog is visible (This is how the JDK behaves.).
            close();
        }

    }

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * Returns the minimum or start value of the operation.
//     *
//     * @return Minimum or start value of the operation.
//     */
//    public int getMinimum() {
//        return min;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * <p>Use this method to set the minimum or start value of
//     * your operation.</p>
//     * <p/>
//     * <p>For typical application like copy operation this will be
//     * zero.</p>
//     * <p/>
//     * <p>Keep in mind that changing this value after the progress
//     * dialog is made visible has no effect upon the progress bar.</p>
//     *
//     * @param minimum The new minimum value.
//     */
//    public void setMinimum(int minimum) {
//        min = minimum;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * Return the maximum or end value of your operation.
//     *
//     * @return Maximum or end value.
//     */
//    public int getMaximum() {
//        return max;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * <p>Sets the maximum or end value of the operation to the
//     * given integer.</p>
//     *
//     * @param maximum i.e., 100
//     */
//    public void setMaximum(int maximum) {
//        max = maximum;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

    /**
     * Returns whether the user canceled the operation.
     *
     * @return Whether the operation was canceled.
     */
    public boolean isCanceled() {
        // The value is predefined to false
        // and changes only when the user clicks
        // the cancel button in the progress dialog.
        return canceled;
    }

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * Returns the amount of milliseconds to wait
//     * until the ProgressMonitor should decide whether
//     * a progress dialog is to be shown or not.
//     *
//     * @return The duration in milliseconds.
//     */
//    public int getMillisToDecideToPopup() {
//        return MILLIS_TO_DECIDE_TO_POPUP;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * Returns the number of milliseconds to wait before displaying the progress
//     * dialog.  The default value is000.
//     *
//     * @return The number of milliseconds.
//     * @see #setMillisToPopup(int)
//     */
//    public int getMillisToPopup() {
//        return millisToPopup;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * Sets the number of milliseconds to wait before displaying the progress
//     * dialog.
//     *
//     * @param time the number of milliseconds.
//     * @see #getMillisToPopup()
//     */
//    public void setMillisToPopup(int time) {
//        millisToPopup = time;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

// --Commented out by Inspection START (4/30/07 5:22 PM):
//    /**
//     * Returns a message which is shown in the progress dialog.
//     *
//     * @return The changeable message visible in the progress dialog.
//     */
//    public String getNote() {
//        return note;
//    }
// --Commented out by Inspection STOP (4/30/07 5:22 PM)

    /**
     * <p>Set the message shown in the progess dialog.</p>
     * <p/>
     * <p>Changing the note while the progress dialog is visible
     * is possible.</p>
     *
     * @param note A message shown in the progress dialog.
     */
    public void setNote(String note) {
        if (noteTextArea != null) {
            noteTextArea.setText(note);
        } else {
            this.note = note;
        }
    }

    /**
     * Internal method that creates the progress dialog.
     */
    void createDialog() {
        //set up for text area
        noteTextArea = new JTextArea(note);
        noteTextArea.setEditable(false);

        scrollPane = new JScrollPane(noteTextArea);
        scrollPane.setBorder(BorderFactory.createEmptyBorder());

        Object[] tmp = note == null ? new Object[]{message, progressBar = new JProgressBar(min, max)} : new Object[]{message, scrollPane, progressBar = new JProgressBar(min, max)};

        JOptionPane pane = new JOptionPane(tmp, JOptionPane.INFORMATION_MESSAGE);

        // FIX Internationalize the button
        JButton cancelButton = new JButton("Cancel");
        cancelButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                canceled = true;
            }
        });

        pane.setOptions(new Object[]{cancelButton});

        // FIX Internationalize the title
        progressDialog = pane.createDialog(component, "Same is running...");
        progressDialog.setPreferredSize(new Dimension(400, 150));
        progressDialog.setModal(false);
        progressDialog.setResizable(true);

        progressDialog.pack();
        progressDialog.setVisible(true);

        // Text Area
        noteTextArea.setBackground(pane.getBackground());
    }

    /**
     * An ActionListener implementation which does the measurements
     * and estimations of the ProgressMonitor.
     */
    class TimerListener implements ActionListener {
        long timestamp;

        // --Commented out by Inspection (4/30/07 5:22 PM):int lastProgress;

        boolean first = true;

        TimerListener() {
            timestamp = System.currentTimeMillis();
        }

        public void actionPerformed(ActionEvent ae) {
            long now = System.currentTimeMillis();

            if (first) {
                if (now - timestamp > MILLIS_TO_DECIDE_TO_POPUP) {
                    first = false;
                    long expected = (now - timestamp) * (max - min) / (progress - min);

                    if (expected > millisToPopup) {
                        createDialog();
                    }
                } else {
                    // We have not waited long enough to make a decision,
                    // so return and try again when the timer is invoked.
                    return;
                }
            } else if (progressDialog != null) {
                // The progress dialog is being displayed. We now calculate
                // whether setting the progress bar to the current progress
                // value would result in a visual difference.
                int delta = progress - progressBar.getValue();

                if (delta * progressBar.getWidth() / (max - min) > 0) {
                    // At least one pixel would change.
                    progressBar.setValue(progress);
                }
            } else {
                // No dialog necessary
                timer.stop();
                timer = null;
            }

            timestamp = now;
        }
    }

}
